﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Xml;
using System.Xml.Serialization;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using System.Text.RegularExpressions;

namespace Expertime.Multitude.Intranet.Emails
{
    public class EmailSender
    {
        #region const
        /// <summary>
        /// Chemin de configuration par défaut de l'emailSender
        /// </summary>
        public const string DEFAULT_EMAIL_CONFIG_PATH = @"layouts\SEM\EmailSender\EmailSender.config";
        #endregion

        #region property
        private static string emailConfigPath = DEFAULT_EMAIL_CONFIG_PATH;
        private static EmailSender mySender;
        #endregion

        #region getter setter
        /// <summary>
        /// Get, Set: Chemin de configuration de l'emailSender
        /// </summary>
        public static string EmailConfigPath
        {
            get { return string.IsNullOrEmpty(emailConfigPath) ? EmailConfigPath_Setting : emailConfigPath; }
            set { emailConfigPath = value; }
        }
        public static string EmailConfigPath_Setting
        {
            get { return ConfigurationManager.AppSettings.AllKeys.Any(k => k == "emailConfigPath") ? ConfigurationManager.AppSettings["emailConfigPath"] : DEFAULT_EMAIL_CONFIG_PATH; }
        }
        public static EmailSender Sender
        {
            get
            {
                SPSecurity.RunWithElevatedPrivileges(delegate()
                {
                    String filePath = Path.Combine(SPUtility.GetGenericSetupPath("template"), EmailConfigPath);
                    //if (ConfigurationManager.AppSettings.AllKeys.Any(k => k == "emailConfigPath"))
                    //{
                    //    filePath = Path.Combine(SPUtility.GetGenericSetupPath("template"), ConfigurationManager.AppSettings["emailConfigPath"]);
                    //}
                    mySender = GetFromXml(filePath);
                });
                return mySender;
            }
        }

        public string CurrentWebUrl { get; set; }

        [XmlArray]
        public List<EmailTemplate> Templates { get; set; }

        private static EmailSender GetFromXml(String filePath)
        {
            var serializer = new XmlSerializer(typeof(EmailSender));
            var stream = File.OpenRead(filePath);
            var newSender = (EmailSender)serializer.Deserialize(stream);
            stream.Close();
            return newSender;
        }
        #endregion

        #region private methods

        /// <summary>
        /// Get a dictionary of parameters (PropertyName => PropertyValue)
        /// </summary>
        /// <typeparam name="T">Binding object type</typeparam>
        /// <param name="BindingObject">Object for binding</param>
        /// <returns>Dictionary of parameters</returns>
        private string GetBindingPropertyValue<T>(T BindingObject, string PropertyBindingName)
        {
            try
            {
                if (PropertyBindingName.Contains("."))
                {
                    string PropertyName = PropertyBindingName.Split('.')[0];
                    string innerPropertyName = PropertyBindingName.Split('.')[1];
                    System.Reflection.PropertyInfo[] destinationProperties = BindingObject.GetType().GetProperties();

                    var property = from elem in destinationProperties
                                   where elem.Name == PropertyName
                                   select elem;

                    if (property != null && property.Count() > 0)
                    {
                        object propertyValue = property.First().GetValue(BindingObject, null);
                        return GetBindingPropertyValue(propertyValue, innerPropertyName);
                    }
                    else
                    {
                        return null;
                    }
                }
                else
                {
                    System.Reflection.PropertyInfo[] destinationProperties = BindingObject.GetType().GetProperties();
                    var property = from elem in destinationProperties
                                   where elem.Name == PropertyBindingName
                                   select elem;

                    if (property != null && property.Count() > 0)
                    {

                        object propertyValue = property.First().GetValue(BindingObject, null);
                        if (propertyValue != null)
                        {
                            if (property.First().PropertyType == typeof(bool))
                                return (propertyValue.ToString().ToLower() == "true" ? "oui" : "non");
                            else
                                return propertyValue.ToString();
                        }
                        else
                            return String.Empty;
                    }
                    else
                    {
                        return null;
                    }
                }
            }
            catch //(Exception ex)
            {
                return null;
            }
        }

        private EmailTemplate ReplaceTemplateValues<T>(EmailTemplate template, IDictionary<String, String> parameters, T bindingObject)
        {
            string pattern = @"#\?([\w|\.]*)\?#";
            Regex r = new Regex(pattern, RegexOptions.IgnoreCase);
            Match m;

            m = r.Match(template.Subject);
            while (m.Success)
            {
                if (m.Groups.Count > 0)
                {
                    Group g = m.Groups[1];

                    if (g.Captures.Count > 0)
                    {
                        Capture c = g.Captures[0];

                        if (parameters.ContainsKey(c.Value))
                        {
                            template.Subject = template.Subject.Replace(String.Format("#?{0}?#", c.Value), parameters[c.Value]);
                        }
                        else
                        {
                            string propertyValue = GetBindingPropertyValue(bindingObject, c.Value);
                            if (propertyValue != null)
                            {
                                template.Subject = template.Subject.Replace(String.Format("#?{0}?#", c.Value), propertyValue);
                            }
                        }
                    }
                }
                m = m.NextMatch();
            }

            m = r.Match(template.Body);
            while (m.Success)
            {
                if (m.Groups.Count > 0)
                {
                    Group g = m.Groups[1];

                    if (g.Captures.Count > 0)
                    {
                        Capture c = g.Captures[0];

                        if (parameters.ContainsKey(c.Value))
                        {
                            template.Body = template.Body.Replace(String.Format("#?{0}?#", c.Value), parameters[c.Value]);
                        }
                        else
                        {
                            string propertyValue = GetBindingPropertyValue(bindingObject, c.Value);
                            if (propertyValue != null)
                            {
                                template.Body = template.Body.Replace(String.Format("#?{0}?#", c.Value), propertyValue);
                            }
                        }
                    }
                }
                m = m.NextMatch();
            }

            return template;
        }
        #endregion

        #region sendmails
        /// <summary>
        /// Send an email
        /// </summary>
        /// <param name="templateName">Template name</param>
        public void SendEmail(String templateName)
        {
            SendEmail(Templates.Single(template => template.Name.Equals(templateName)));
        }

        /// <summary>
        /// Send a email
        /// </summary>
        /// <param name="templateName">Template name</param>
        /// <param name="parameters">Parameters</param>
        public void SendEmail(String templateName, IDictionary<String, String> parameters)
        {
            EmailTemplate template = Templates.Single(t => t.Name.Equals(templateName));
            foreach (String key in parameters.Keys)
            {
                template.Subject = template.Subject.Replace(String.Format("#?{0}?#", key), parameters[key]);
                template.Body = template.Body.Replace(String.Format("#?{0}?#", key), parameters[key]);
            }
            SendEmail(template);
        }

        /// <summary>
        /// Send a email
        /// </summary>
        /// <param name="templateName">Template name</param>
        /// <param name="parameters">Parameters</param>
        /// <param name="bindingObject">Object for properties binding</param>
        public void SendEmail<T>(String templateName, IDictionary<String, String> parameters, T bindingObject)
        {
            EmailTemplate template = Templates.Single(t => t.Name.Equals(templateName));
            template = ReplaceTemplateValues(template, parameters, bindingObject);
            SendEmail(template);
        }



        /// <summary>
        /// Send a email
        /// </summary>
        /// <param name="templateName">Template name</param>
        /// <param name="body">Email body</param>
        public void SendEmail(String templateName, String body)
        {
            EmailTemplate template = Templates.Single(t => t.Name.Equals(templateName));
            template.Body = body;
            SendEmail(template);
        }

        /// <summary>
        /// Send an email
        /// </summary>
        /// <param name="templateName">Template name</param>
        /// <param name="from">Email sender</param>
        public void SendEmailWithSender(String templateName, String from)
        {
            EmailTemplate template = Templates.Single(t => t.Name.Equals(templateName));
            template.From = from;
            SendEmail(template);
        }

        /// <summary>
        /// Send an email
        /// </summary>
        /// <param name="templateName">Template name</param>
        /// <param name="from">Email sender</param>
        /// <param name="body">Email body</param>
        public void SendEmailWithSender(String templateName, String from, String body)
        {
            EmailTemplate template = Templates.Single(t => t.Name.Equals(templateName));
            template.From = from;
            template.Body = body;
            SendEmail(template);
        }

        /// <summary>
        /// Send an email
        /// </summary>
        /// <param name="templateName">Template name</param>
        /// <param name="from">Email sender</param>
        /// <param name="parameters">Parameters</param>
        public void SendEmailWithSender(String templateName, String from, IDictionary<String, String> parameters)
        {
            EmailTemplate template = Templates.Single(t => t.Name.Equals(templateName));
            template.From = from;
            foreach (String key in parameters.Keys)
            {
                template.Subject = template.Subject.Replace(String.Format("#?{0}?#", key), parameters[key]);
                template.Body = template.Body.Replace(String.Format("#?{0}?#", key), parameters[key]);
            }
            SendEmail(template);
        }

        /// <summary>
        /// Send an email
        /// </summary>
        /// <param name="templateName">Template name</param>
        /// <param name="from">Email sender</param>
        /// <param name="parameters">Parameters</param>
        /// <param name="bindingObject">Object for properties binding</param>
        public void SendEmailWithSender<T>(String templateName, String from, IDictionary<String, String> parameters, T bindingObject)
        {
            EmailTemplate template = Templates.Single(t => t.Name.Equals(templateName));
            template.From = from;
            template = ReplaceTemplateValues(template, parameters, bindingObject);
            SendEmail(template);
        }

        /// <summary>
        /// Send an email
        /// </summary>
        /// <param name="templateName">Template name</param>
        /// <param name="to">Email receiver</param>
        public void SendEmailWithReceiver(String templateName, String to)
        {
            EmailTemplate template = Templates.Single(t => t.Name.Equals(templateName));
            template.To = to;
            SendEmail(template);
        }

        /// <summary>
        /// Send an email
        /// </summary>
        /// <param name="templateName">Template name</param>
        /// <param name="to">Email receiver</param>
        /// <param name="parameters">Parameters</param>
        public bool SendEmailWithReceiver(SPWeb currentWeb, String templateName, String to, IDictionary<String, String> parameters)
        {
            EmailTemplate template = Templates.Single(t => t.Name.Equals(templateName));
            template.To = to;
            foreach (String key in parameters.Keys)
            {
                template.Subject = template.Subject.Replace(String.Format("#?{0}?#", key), parameters[key]);
                template.Body = template.Body.Replace(String.Format("#?{0}?#", key), parameters[key]);
            }
            return SendEmail(currentWeb, template);
        }

        /// <summary>
        /// Send an email
        /// </summary>
        /// <param name="templateName">Template name</param>
        /// <param name="to">Email sender</param>
        /// <param name="parameters">Parameters</param>
        /// <param name="bindingObject">Object for properties binding</param>
        public void SendEmailWithReceiver<T>(String templateName, String to, IDictionary<String, String> parameters, T bindingObject)
        {

            EmailTemplate template = Templates.Single(t => t.Name.Equals(templateName));
            template.To = to;
            template = ReplaceTemplateValues(template, parameters, bindingObject);
            SendEmail(template);
        }

        /// <summary>
        /// Send an email
        /// </summary>
        /// <param name="templateName">Template name</param>
        /// <param name="to">Email receiver</param>
        /// <param name="body">Email body</param>
        public void SendEmailWithReceiver(SPWeb currentWeb, String templateName, String to, String body)
        {
            EmailTemplate template = Templates.Single(t => t.Name.Equals(templateName));
            template.To = to;
            template.Body = body;
            SendEmail(currentWeb, template);
        }

        /// <summary>
        /// Send an email
        /// </summary>
        /// <param name="templateName">Template name</param>
        /// <param name="from">Email sender</param>
        /// <param name="to">Email receiver</param>
        public void SendEmail(String templateName, String from, String to)
        {
            EmailTemplate template = Templates.Single(t => t.Name.Equals(templateName));
            template.From = from;
            template.To = to;
            SendEmail(template);
        }

        /// <summary>
        /// Send an email
        /// </summary>
        /// <param name="template">Email template</param>
        public bool SendEmail(EmailTemplate template)
        {
            return SendEmail(SPContext.Current.Web, template);
        }
        /// <summary>
        /// Send an email
        /// </summary>
        /// <param name="web">Current web to send mail</param>
        /// <param name="template">Email template</param>
        public bool SendEmail(SPWeb web, EmailTemplate template)
        {
            try
            {
                return SPUtility.SendEmail(web, false, false, template.To, template.Subject, template.Body, false);
            }
            catch (Exception)
            {
                return false;
            }
        }
        #endregion

        #region get
        /// <summary>
        /// Get an email
        /// </summary>
        /// <param name="templateName">Template name</param>
        public EmailTemplate GetEmail(String templateName)
        {
            return Templates.Single(template => template.Name.Equals(templateName));
        }

        /// <summary>
        /// Get an email
        /// </summary>
        /// <param name="templateName">Template name</param>
        /// <param name="body">Email body</param>
        public EmailTemplate GetEmail(String templateName, String body)
        {
            EmailTemplate template = Templates.Single(t => t.Name.Equals(templateName));
            template.Body = body;
            return template;
        }

        /// <summary>
        /// Get an email
        /// </summary>
        /// <param name="templateName">Template name</param>
        /// <param name="from">Email sender</param>
        public EmailTemplate GetEmailWithSender(String templateName, String from)
        {
            EmailTemplate template = Templates.Single(t => t.Name.Equals(templateName));
            template.From = from;
            return template;
        }

        /// <summary>
        /// Get an email
        /// </summary>
        /// <param name="templateName">Template name</param>
        /// <param name="from">Email sender</param>
        /// <param name="body">Email body</param>
        public EmailTemplate GetEmailWithSender(String templateName, String from, String body)
        {
            EmailTemplate template = Templates.Single(t => t.Name.Equals(templateName));
            template.From = from;
            template.Body = body;
            return template;
        }

        /// <summary>
        /// Get an email
        /// </summary>
        /// <param name="templateName">Template name</param>
        /// <param name="from">Email sender</param>
        /// <param name="parameters">Parameters</param>
        public EmailTemplate GetEmailWithSender(String templateName, String from, IDictionary<String, String> parameters)
        {
            EmailTemplate template = Templates.Single(t => t.Name.Equals(templateName));
            template.From = from;
            foreach (String key in parameters.Keys)
            {
                template.Subject = template.Subject.Replace(String.Format("#?{0}?#", key), parameters[key]);
                template.Body = template.Body.Replace(String.Format("#?{0}?#", key), parameters[key]);
            }
            return template;
        }

        /// <summary>
        /// Get an email
        /// </summary>
        /// <param name="templateName">Template name</param>
        /// <param name="to">Email receiver</param>
        public EmailTemplate GetEmailWithReceiver(String templateName, String to)
        {
            EmailTemplate template = Templates.Single(t => t.Name.Equals(templateName));
            template.To = to;
            return template;
        }

        /// <summary>
        /// Get an email
        /// </summary>
        /// <param name="templateName">Template name</param>
        /// <param name="to">Email receiver</param>
        /// <param name="parameters">Parameters</param>
        public EmailTemplate GetEmailWithReceiver(String templateName, String to, IDictionary<String, String> parameters)
        {
            EmailTemplate template = Templates.Single(t => t.Name.Equals(templateName));
            template.To = to;
            foreach (String key in parameters.Keys)
            {
                template.Subject = template.Subject.Replace(String.Format("#?{0}?#", key), parameters[key]);
                template.Body = template.Body.Replace(String.Format("#?{0}?#", key), parameters[key]);
            }
            return template;
        }

        /// <summary>
        /// Get an email
        /// </summary>
        /// <param name="templateName">Template name</param>
        /// <param name="to">Email receiver</param>
        /// <param name="body">Email body</param>
        public EmailTemplate GetEmailWithReceiver(String templateName, String to, String body)
        {
            EmailTemplate template = Templates.Single(t => t.Name.Equals(templateName));
            template.To = to;
            template.Body = body;
            return template;
        }

        /// <summary>
        /// Get an email
        /// </summary>
        /// <param name="templateName">Template name</param>
        /// <param name="from">Email sender</param>
        /// <param name="to">Email receiver</param>
        public EmailTemplate GetEmail(String templateName, String from, String to)
        {
            EmailTemplate template = Templates.Single(t => t.Name.Equals(templateName));
            template.From = from;
            template.To = to;
            return template;
        }
        #endregion


    }
}
